﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using Loki.Commands;
using Loki.IoC;

namespace Loki.Utils
{
    /// <summary>
    /// Loki services helper class.
    /// </summary>
    public static class Toolkit
    {
        #region Extensibility

        private const string DefaultEngine = "Windsor";
        private const string DefaultLogger = "Log4Net";
        private static ExtensionManager<IIoCComponent> engineManager;
        private static ExtensionManager<ILoggerComponent> loggerManager;

        /// <summary>
        /// Initializes the toolkit.
        /// </summary>
        public static void Initialize()
        {
            InitializeLogger();

            InitializeEngine();
        }

        private static void InitializeEngine()
        {
            engineManager = new ExtensionManager<IIoCComponent>(DefaultEngine);
            engineManager.Initialize();

            if (IoC != null)
            {
                IoC.Initialize();
                context = new Lazy<IObjectContext>(CreateContext);
            }
        }

        private static void InitializeLogger()
        {
            loggerManager = new ExtensionManager<ILoggerComponent>(DefaultLogger);
            loggerManager.Initialize();
        }

        #endregion Extensibility

        #region Object Context

        private const string ToolkitContextName = "Loki";

        private static Lazy<IObjectContext> context;

        private static List<IContextInstaller> installers = new List<IContextInstaller>(new IContextInstaller[] { new LokiServicesInstaller() });

        /// <summary>
        /// Gets the toolkit context.
        /// </summary>
        /// <value>
        /// The context.
        /// </value>
        public static IObjectContext Context
        {
            get
            {
                if (context == null)
                {
                    Trace.Fail(Resources.ErrorMessages.Utils_Toolkit_NotInitialized);
                }

                return context.Value;
            }
        }

        public static IEnumerable<IContextInstaller> Installers
        {
            get { return installers; }
        }

        /// <summary>
        /// Registers an additional installer for the toolkit.
        /// </summary>
        /// <param name="installer">The installer.</param>
        public static void RegisterInstaller(IContextInstaller installer)
        {
            installers.Add(installer);
        }

        /// <summary>
        /// Resets the toolkit.
        /// </summary>
        public static void Reset()
        {
            if (context.IsValueCreated)
            {
                Context.Dispose();
            }

            Logger.DisposeIfDisposable();
            IoC.DisposeIfDisposable();

            Initialize();
        }

        private static IObjectContext CreateContext()
        {
            try
            {
                return IoC.DefaultContext;
            }
            catch (Exception exception)
            {
                Trace.Fail(exception.Message);
                throw;
            }
        }

        #endregion Object Context

        private static Lazy<ICommandComponent> commands = new Lazy<ICommandComponent>(() => Context.Get<ICommandComponent>());

        private static Lazy<IErrorComponent> errors = new Lazy<IErrorComponent>(() => Context.Get<IErrorComponent>());

        private static Lazy<IEventComponent> events = new Lazy<IEventComponent>(() => Context.Get<IEventComponent>());

        private static Lazy<IMessageComponent> messages = new Lazy<IMessageComponent>(() => Context.Get<IMessageComponent>());

        private static Lazy<ISettingsComponent> settings = new Lazy<ISettingsComponent>(() => Context.Get<ISettingsComponent>());

        private static Lazy<ITaskComponent> tasks = new Lazy<ITaskComponent>(() => Context.Get<ITaskComponent>());

        /// <summary>
        /// Gets the command service.
        /// </summary>
        /// <value>The configured command service.</value>
        public static ICommandComponent Commands
        {
            get
            {
                return commands.Value;
            }
        }

        /// <summary>
        /// Gets the engine service.
        /// </summary>
        public static IIoCComponent IoC
        {
            get
            {
                return engineManager.SelectedComponent;
            }
        }

        /// <summary>
        /// Gets the error service.
        /// </summary>
        public static IErrorComponent ErrorManager
        {
            get
            {
                return errors.Value;
            }
        }

        /// <summary>
        /// Gets the event service.
        /// </summary>
        public static IEventComponent Events
        {
            get
            {
                return events.Value;
            }
        }

        /// <summary>
        /// Gets the logger service.
        /// </summary>
        /// <value>The configured logger service.</value>
        public static ILoggerComponent Logger
        {
            get
            {
                return loggerManager.SelectedComponent;
            }
        }

        /// <summary>
        /// Gets the message bus.
        /// </summary>
        /// <value>
        /// The message bus.
        /// </value>
        public static IMessageComponent MessageBus
        {
            get
            {
                return messages.Value;
            }
        }

        /// <summary>
        /// Gets the settings service.
        /// </summary>
        /// <value>The configured settings service.</value>
        public static ISettingsComponent Settings
        {
            get
            {
                return settings.Value;
            }
        }

        /// <summary>
        /// Gets the task service.
        /// </summary>
        public static ITaskComponent Tasks
        {
            get
            {
                return tasks.Value;
            }
        }
    }
}